﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using StructureMap;
using System.Collections.Generic;

namespace Smugmug.Tests
{
    [TestClass]
    public class ApiTests
    {
        public TestContext TestContext { get; set; }
        private IEnumerable<IProtocol> Protocols
        {
            get
            {
                yield return new RestProtocol();
                yield return new JsonProtocol();
            }
        }

        [TestInitialize]
        public void Setup()
        {
            StructureMapConfiguration.AddInstanceOf<IProtocol>().UsingConcreteType<RestProtocol>();
            StructureMapConfiguration.AddInstanceOf<IWebClient>().UsingConcreteType<TestWebClient>();
            StructureMapConfiguration.AddInstanceOf<ILogger>().UsingConcreteType<NLogLogger>();
            StructureMapConfiguration.AddInstanceOf<SmugmugClient>().UsingConcreteType<SmugmugClient>()
                .WithProperty("version").EqualTo(Config.ServiceVersion);
        }

        #region Test Helper Methods

        /// <summary>
        /// Verifies that the given action does in fact throw a SmugmugException and
        /// that the FaultCode is correct.
        /// </summary>
        private void ExceptionTest(Action<SmugmugClient> action, FaultCode expectedCode)
        {
            SmugmugClient client = ObjectFactory.GetInstance<SmugmugClient>();

            foreach (IProtocol protocol in Protocols)
            {
                client.Protocol = protocol;
                bool exceptionCaught = false;
                try
                {
                    action.Invoke(client);
                }
                catch (SmugmugException ex)
                {
                    exceptionCaught = true;
                    Assert.AreEqual(expectedCode, ex.Error);
                }
                Assert.IsTrue(exceptionCaught, "The expected exception was not thrown by the call " + action.Method.Name);
            }
        }

        private void ExceptionTest<T>(Action<SmugmugClient> action)
            where T : Exception
        {
            SmugmugClient client = ObjectFactory.GetInstance<SmugmugClient>();

            foreach (IProtocol protocol in Protocols)
            {
                client.Protocol = protocol;
                bool exceptionCaught = false;
                try
                {
                    action.Invoke(client);
                }
                catch (Exception e)
                {
                    exceptionCaught = true;
                    Assert.IsTrue(e is T);
                }
                Assert.IsTrue(exceptionCaught, "The expected exception (" + typeof(T).ToString() + ") was not thrown by the call " + action.Method.Name);
            }
        }

        /// <summary>
        /// Verifies that the given action returns an object which is not null.
        /// </summary>
        private void NotNullTest<T>(Func<SmugmugClient, T> action)
        {
            SmugmugClient client = ObjectFactory.GetInstance<SmugmugClient>();

            foreach (IProtocol protocol in Protocols)
            {
                client.Protocol = protocol;
                T item = action.Invoke(client);
                Assert.IsNotNull(item);
            }
        }

        #endregion

        #region Login

        #region Login Anonymously

        [TestMethod]
        public void Login_LoginAnonymously_DeserializesCorrectly()
        {
            NotNullTest<Login>(client => client.LoginAnonymously(Config.ApiKey, null, null, null));
        }

        [TestMethod]
        public void Login_LoginAnonymously_EmptyApiKey_ReturnsInvalidApiKey()
        {
            ExceptionTest(client => client.LoginAnonymously("", null, null, null), FaultCode.InvalidApiKey);
        }

        [TestMethod]
        public void Login_LoginAnonymously_NullApiKey_ReturnsInvalidApiKey()
        {
            ExceptionTest(client => client.LoginAnonymously(null, null, null, null), FaultCode.InvalidApiKey);
        }

        [TestMethod]
        public void Login_LoginAnonymously_InvalidApiKey_ReturnsInvalidApiKey()
        {
            ExceptionTest(client => client.LoginAnonymously(TestValues.InvalidApiKey, null, null, null), FaultCode.InvalidApiKey);
        }

        #endregion        

        #region Login With Password

        [TestMethod]
        public void Login_LoginWithPassword_DeserializesCorrectly()
        {
            Assert.IsFalse(String.IsNullOrEmpty(Config.ApiKey));

            NotNullTest<Login>(client => client.LoginWithPassword(Config.ApiKey, "xxxx", "xxxx", null, null, null));
        }

        [TestMethod]
        public void Login_LoginWithPassword_NullUserName_ReturnsInvalidLogin()
        {
            ExceptionTest(client => client.LoginWithPassword(TestValues.ApiKey, null, "", null, null, null), FaultCode.InvalidApiKey);
        }

        [TestMethod]
        public void Login_LoginWithPassword_InvalidUserName_ReturnsInvalidLogin()
        {
            ExceptionTest(client => client.LoginWithPassword(TestValues.ApiKey, TestValues.UserName, TestValues.Password, null, null, null), FaultCode.InvalidLogin);
        }

        #endregion

        #region Login With Hash

        [TestMethod]
        public void Login_LoginWithHash_ValidHash_DeserializesCorrectly()
        {
            NotNullTest<Login>(client => client.LoginWithHash(Config.UserId.Value, Config.PasswordHash, Config.ApiKey, null, null, null));
        }

        [TestMethod]
        public void Login_LoginWithHash_InvalidHash_ReturnsInvalidLogin()
        {
            ExceptionTest(client => client.LoginWithHash(TestValues.UserId, TestValues.InvalidHash, TestValues.ApiKey, null, null, null), FaultCode.InvalidLogin);
        }

        #endregion

        #endregion

        #region Images

        //[TestMethod]
        public void Image_GetImageUrls_DeserializesCorrectly()
        {
            NotNullTest<Image>(client => client.GetImageUrls("session", 0, TemplateType.Journal, "password", "sitePassword", "ImageKey"));
        }

        //[TestMethod]
        public void Image_GetImages_DeserializesCorrectly()
        {
            NotNullTest<ImageCollection>(client => client.GetImages("session", 0, true, "password", "sitePassword", "albumKey"));
        }

        #endregion

        #region Albums

        //void ApplyAlbumWatermark(string sessionId, int albumId, string callback, bool? pretty, bool? strict, int watermarkId)
        [TestMethod]
        public void Albums_ApplyWatermark_NullSessionId_ThrowsException()
        {
            ExceptionTest<ArgumentNullException>(client => client.ApplyAlbumWatermark(null, 0, null, null, null, 0));
        }
        

        //[TestMethod]
        public void Image_GetAlbums_DeserializesCorrectly()
        {
            NotNullTest<AlbumCollection>(client => client.GetAlbums("session", null, "extras", true, 0, "nickName", false, "pwd", false));
        }

        //[TestMethod]
        //[ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void EmptySessionID_ThrowsException()
        {
            SmugmugClient client = ObjectFactory.GetInstance<SmugmugClient>();
            Album a = client.GetAlbumInfo("session", 0, "key", null, null, null, null, null);
        }

        #endregion
    }
}
